package ipc;

import java.util.Random;
import ipc.Simulator;
import ipc.State;
import ipc.Node;
import java.util.List;
import java.util.ArrayList;


public class StateNode<S extends State, A> extends Node<S,A>{
        private S state_;
	public static String inst_name;

        public StateNode(S state, List<A> legalActions) {
            state_ = state;
            children = new ArrayList<Node<S,A>>(legalActions.size());
            for (A action : legalActions)
                children.add(new ActionNode(action));
        }

        @Override
        public int hashCode(){
		throw new RuntimeException("Told you not to use hashcode...");
        }
		
        /**
         * Select child node with best UCT value. Always play a random
         * unexplored action first.
         * 
         * @return an action child node.
         */

	public Node<S,A> selectChild(Simulator<S,A> sim, Random _rand, int depth){
//	    System.err.println("state node ");	
            List<Node<S, A>> unvisited = new ArrayList<Node<S, A>>();

            for (Node<S, A> child : children){
                if (child.getVisits() == 0 )
                    unvisited.add(child);
	    }

	
            if( unvisited.size() != 0){
            	Node<S, A> selected = unvisited.get((int) (_rand.nextDouble() * unvisited.size()));
                return selected;
            }

            double bestUctVal = Double.NEGATIVE_INFINITY;
            int  bestUctIndex = -1;
  		
	    double C;
	    try{
	    	C = SPUDDer.getRange(inst_name, depth);          
	    }catch(Exception e){
		Main.exceptionLog.log("Could not get range from spudd... resorting to self max");
			C = Math.abs(MAXV-MINV);
			C = (C == 0)? 1: C; 
	    }

            for (int i = 0 ; i < children.size(); ++i ) {
		Node<S,A> child = children.get(i);

            	double qsa = (((double) child.getReward(state_.getAgentTurn())) / child.getVisits()); 
                double uctValue = qsa + C* Math.sqrt(Math.log(getVisits()) / child.getVisits());
                if ( uctValue > bestUctVal ) {
                    bestUctVal = uctValue;
		    bestUctIndex = i;	
                }
            }
	
	    if( bestUctIndex == -1 ){
			Main.exceptionLog.log("Something wrong here -- vestIndex = -1 ");
		}
	    return children.get(bestUctIndex);		
        }

        public S getState() {
            return state_;
        }

	public Node<S,A> getMaxChild(){
	    double bestVal = Double.NEGATIVE_INFINITY;
        int bestIndex = -1;
  		
        for (int i = 0 ; i < children.size(); ++i ) {
        	Node<S,A> child = children.get(i);
        	if( child.getVisits() == 0 )
        		continue;
        	double qsa = (((double) child.getReward(state_.getAgentTurn())) / child.getVisits()); 
            if ( qsa > bestVal ) {
                bestVal = qsa;
                bestIndex = i;	
            }
        }
	
	    if( bestIndex == -1 ){
			Main.exceptionLog.log("returning noop");
			bestIndex = 0;
		}
	    
	    return ((ActionNode<S,A>)children.get(bestIndex));		
	}

	@Override
	public boolean equals(Object o){
//		System.err.println("here");
		return this.state_.equals(((StateNode<S,A>)o).getState());
	}   	

	@Override
	public String toString(){
		return "STATENODE: " + this.visits_ + " " + this.rewards_ + " " + state_.toString()+"\n"+children.toString();
	}
	
}
